package pl.edu.pw.perg.compinfodb.xls.to;

import static pl.edu.pw.perg.compinfodb.xls.XLSConstants.*;
import static pl.edu.pw.perg.compinfodb.xls.XLSConstants.CONNECTIONS_SHEET;
import static pl.edu.pw.perg.compinfodb.xls.XLSConstants.CON_CBL_COL;
import static pl.edu.pw.perg.compinfodb.xls.XLSConstants.CON_IN_CON_COL;
import static pl.edu.pw.perg.compinfodb.xls.XLSConstants.CON_IN_ELT_COL;
import static pl.edu.pw.perg.compinfodb.xls.XLSConstants.CON_OUT_CON_COL;
import static pl.edu.pw.perg.compinfodb.xls.XLSConstants.CON_OUT_ELT_COL;
import static pl.edu.pw.perg.compinfodb.xls.XLSConstants.ELT_ATTRIBUTES_COL;
import static pl.edu.pw.perg.compinfodb.xls.XLSConstants.ELT_ID_COL;
import static pl.edu.pw.perg.compinfodb.xls.XLSConstants.ELT_LABEL_COL;
import static pl.edu.pw.perg.compinfodb.xls.XLSConstants.ELT_TYPE_COL;
import static pl.edu.pw.perg.compinfodb.xls.XLSConstants.FIELDS_SHEET;
import static pl.edu.pw.perg.compinfodb.xls.XLSConstants.FIELD_FIELD_NAME_COL;
import static pl.edu.pw.perg.compinfodb.xls.XLSConstants.HEADER_ROWS;
import static pl.edu.pw.perg.compinfodb.xls.XLSConstants.HISTORY_SHEET;
import static pl.edu.pw.perg.compinfodb.xls.XLSConstants.HIST_AUTHOR_COL;
import static pl.edu.pw.perg.compinfodb.xls.XLSConstants.HIST_COMMENT_COL;
import static pl.edu.pw.perg.compinfodb.xls.XLSConstants.HIST_DATE_COL;
import static pl.edu.pw.perg.compinfodb.xls.XLSConstants.HIST_ELEMENT_COL;
import static pl.edu.pw.perg.compinfodb.xls.XLSConstants.HIST_MODULE_COL;
import static pl.edu.pw.perg.compinfodb.xls.XLSConstants.MODULES_SHEET;
import static pl.edu.pw.perg.compinfodb.xls.XLSConstants.STRUCTURE_SHEET;
import static pl.edu.pw.perg.compinfodb.xls.XLSConstants.STRUCT_ID_COL;
import static pl.edu.pw.perg.compinfodb.xls.XLSConstants.STRUCT_LOCATION_COL;
import static pl.edu.pw.perg.compinfodb.xls.XLSConstants.STRUCT_PARENT_COL;
import static pl.edu.pw.perg.compinfodb.xls.XLSConstants.STRUCT_TYPE_COL;
import static pl.edu.pw.perg.compinfodb.xls.XLSConstants.TYPES_SHEET;
import static pl.edu.pw.perg.compinfodb.xls.XLSConstants.TYPE_CABLE_COL;
import static pl.edu.pw.perg.compinfodb.xls.XLSConstants.TYPE_ELEMENT_TYPE_COL;
import static pl.edu.pw.perg.compinfodb.xls.XLSConstants.TYPE_FIELDS_COL;
import static pl.edu.pw.perg.compinfodb.xls.XLSConstants.TYPE_FIRST_INDEX_IN_COL;
import static pl.edu.pw.perg.compinfodb.xls.XLSConstants.TYPE_FIRST_INDEX_OUT_COL;
import static pl.edu.pw.perg.compinfodb.xls.XLSConstants.TYPE_INPUTS_COL;
import static pl.edu.pw.perg.compinfodb.xls.XLSConstants.TYPE_OUTPUTS_COL;
import static pl.edu.pw.perg.compinfodb.xls.XLSConstants.TYPE_PARENT_COL;
import static pl.edu.pw.perg.compinfodb.xls.XLSConstants.XLS_FILE_EXPORT;
import static pl.edu.pw.perg.compinfodb.xls.XLSConstants.dateFormat;
import static pl.edu.pw.perg.compinfodb.xls.XLSUtils.getColumnMap;
import static pl.edu.pw.perg.compinfodb.xls.XLSUtils.getColumnNr;
import static pl.edu.pw.perg.compinfodb.xls.XLSUtils.getIntegerProperty;
import static pl.edu.pw.perg.compinfodb.xls.XLSUtils.getProperty;

import java.io.File;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import jxl.Workbook;
import jxl.write.Label;
import jxl.write.WritableCell;
import jxl.write.WritableSheet;
import jxl.write.WritableWorkbook;
import jxl.write.WriteException;
import jxl.write.biff.RowsExceededException;
import pl.edu.pw.perg.compinfodb.entities.Attribute;
import pl.edu.pw.perg.compinfodb.entities.Connector;
import pl.edu.pw.perg.compinfodb.entities.ConnectorName;
import pl.edu.pw.perg.compinfodb.entities.ElementType;
import pl.edu.pw.perg.compinfodb.entities.Field;
import pl.edu.pw.perg.compinfodb.entities.HistoryItem;
import pl.edu.pw.perg.compinfodb.entities.ModuleHistoryItem;
import pl.edu.pw.perg.compinfodb.entities.PhysicalElement;
import pl.edu.pw.perg.compinfodb.entities.StructureHistoryItem;
import pl.edu.pw.perg.compinfodb.entities.VirtualElement;

public class XLSMetadataWriter {

	private WritableWorkbook workbook;
	private static final Logger logger = LoggerFactory
			.getLogger(XLSMetadataWriter.class);
	private static int sheetIndex = 0;
	private static int HEADER_ROWS_NR;

	public XLSMetadataWriter() {
		try {
			workbook = Workbook.createWorkbook(new File(getProperty(XLS_FILE_EXPORT)));
			for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
				workbook.removeSheet(i);
				save();
			}
			HEADER_ROWS_NR = getIntegerProperty(HEADER_ROWS);

		} catch (IOException e) {
			logger.error("Problem in opening the file: "
					+ getProperty(XLS_FILE_EXPORT), e);
			System.exit(1);
		} catch (WriteException e) {
			logger.error("Clean file failed - cannot write to file: "
					+ getProperty(XLS_FILE_EXPORT), e);
			System.exit(1);
		}
	}

	public void setFields(List<Field> fields) throws RowsExceededException,
			WriteException, IOException {

		WritableSheet sheet = workbook.createSheet(getProperty(FIELDS_SHEET),
				sheetIndex++);
		String[] propertiesList = { FIELD_FIELD_NAME_COL };

		Map<String, Integer> columnMap = getColumnMap(propertiesList);
		for (String columnName : columnMap.keySet()) {
			WritableCell headerCell = new Label(columnMap.get(columnName), 0,
					columnName);
			sheet.addCell(headerCell);
		}

		for (int i = 0; i < fields.size(); i++) {
			Field current = fields.get(i);
			String name = current.getFieldName();
			int row = i + HEADER_ROWS_NR;
			WritableCell nameCell = new Label(
					getColumnNr(FIELD_FIELD_NAME_COL), row, name);
			sheet.addCell(nameCell);
		}

	}

	public void setTypes(List<ElementType> types) throws RowsExceededException,
			WriteException {
		WritableSheet sheet = workbook.createSheet(getProperty(TYPES_SHEET),
				sheetIndex++);
		String[] propertiesList = { TYPE_ELEMENT_TYPE_COL, TYPE_FIELDS_COL,
				TYPE_FIRST_INDEX_IN_COL, TYPE_FIRST_INDEX_OUT_COL, TYPE_INPUTS_COL, TYPE_OUTPUTS_COL,
				TYPE_PARENT_COL, TYPE_CABLE_COL };

		Map<String, Integer> columnMap = getColumnMap(propertiesList);
		for (String columnName : columnMap.keySet()) {
			WritableCell headerCell = new Label(columnMap.get(columnName), 0,
					columnName);
			sheet.addCell(headerCell);
		}

		for (int i = 0; i < types.size(); i++) {
			ElementType current = types.get(i);
			String name = current.getTypeName();
			int row = i + HEADER_ROWS_NR;
			WritableCell nameCell = new Label(
					getColumnNr(TYPE_ELEMENT_TYPE_COL), row, name);
			sheet.addCell(nameCell);

			String inputConns = "" + current.getInputConnectorsNr();
			WritableCell inputCell = new Label(getColumnNr(TYPE_INPUTS_COL),
					row, inputConns);
			sheet.addCell(inputCell);

			String outputConns = "" + current.getOutputConnectorsNr();
			WritableCell outputCell = new Label(getColumnNr(TYPE_OUTPUTS_COL),
					row, outputConns);
			sheet.addCell(outputCell);

			String parent = current.getParentType() == null ? "" : current
					.getParentType().getTypeName();
			WritableCell parentCell = new Label(getColumnNr(TYPE_PARENT_COL),
					row, parent);
			sheet.addCell(parentCell);

			String cable = current.isCable() ? "1" : "0";
			WritableCell cableCell = new Label(getColumnNr(TYPE_CABLE_COL),
					row, cable);
			sheet.addCell(cableCell);

			String firstIndexIn = "" + current.getFirstIndexIn();
			WritableCell firstIndexInCell = new Label(
					getColumnNr(TYPE_FIRST_INDEX_IN_COL), row, firstIndexIn);
			sheet.addCell(firstIndexInCell);
			
			String firstIndexOut = "" + current.getFirstIndexOut();
			WritableCell firstIndexOutCell = new Label(
					getColumnNr(TYPE_FIRST_INDEX_OUT_COL), row, firstIndexOut);
			sheet.addCell(firstIndexOutCell);

			List<Field> fields = new LinkedList<Field>();
			fields.addAll(current.getFields());
			for (int j = 0; j < fields.size(); j++) {
				String fieldName = fields.get(j).getFieldName();
				WritableCell fieldCell = new Label(getColumnNr(TYPE_FIELDS_COL)
						+ j, row, fieldName);
				sheet.addCell(fieldCell);
			}

		}
	}

	public void setConnections(List<Connector> connectors)
			throws RowsExceededException, WriteException {
		WritableSheet sheet = workbook.createSheet(
				getProperty(CONNECTIONS_SHEET), sheetIndex++);
		String[] propertiesList = { CON_CBL_COL, CON_IN_CON_COL,
				CON_IN_ELT_COL, CON_OUT_CON_COL, CON_OUT_ELT_COL };

		Map<String, Integer> columnMap = getColumnMap(propertiesList);
		for (String columnName : columnMap.keySet()) {
			WritableCell headerCell = new Label(columnMap.get(columnName), 0,
					columnName);
			sheet.addCell(headerCell);
		}

		for (int i = 0; i < connectors.size(); i++) {
			Connector conn = connectors.get(i);
			String cableName = conn.getCable() == null ? "" : conn.getCable()
					.getName();
			int row = i + HEADER_ROWS_NR;
			WritableCell cableCell = new Label(getColumnNr(CON_CBL_COL), row,
					cableName);
			sheet.addCell(cableCell);

			String eltIn = conn.getElementIn() == null ? "" : conn
					.getElementIn().getName();
			WritableCell eltinCell = new Label(getColumnNr(CON_IN_ELT_COL),
					row, eltIn);
			sheet.addCell(eltinCell);

			String eltOut = conn.getElementOut() == null ? "" : conn
					.getElementOut().getName();
			WritableCell eltOutCell = new Label(getColumnNr(CON_OUT_ELT_COL),
					row, eltOut);
			sheet.addCell(eltOutCell);

			String posIn = "" + conn.getPositionIn();
			WritableCell posInCell = new Label(getColumnNr(CON_IN_CON_COL),
					row, posIn);
			sheet.addCell(posInCell);

			String posOut = "" + conn.getPositionOut();
			WritableCell posOutCell = new Label(getColumnNr(CON_OUT_CON_COL),
					row, posOut);
			sheet.addCell(posOutCell);

		}
	}

	public void setConnectorNames(List<ConnectorName> connectors)
			throws RowsExceededException, WriteException {
		WritableSheet sheet = workbook.createSheet(
				getProperty(CONNECTOR_NAMES_SHEET), sheetIndex++);
		String[] propertiesList = { CN_INPUT_INDEX_COL, CN_NAME_COL,
				CN_OUTPUT_INDEX_COL, CN_TYPE_COL };

		Map<String, Integer> columnMap = getColumnMap(propertiesList);
		for (String columnName : columnMap.keySet()) {
			WritableCell headerCell = new Label(columnMap.get(columnName), 0,
					columnName);
			sheet.addCell(headerCell);
		}

		for (int i = 0; i < connectors.size(); i++) {
			ConnectorName conn = connectors.get(i);
			String name = conn.getName();
			int row = i + HEADER_ROWS_NR;
			WritableCell nameCell = new Label(getColumnNr(CN_NAME_COL), row,
					name);
			sheet.addCell(nameCell);

			String type = conn.getType() == null ? "" : conn.getType()
					.getTypeName();
			WritableCell eltinCell = new Label(getColumnNr(CN_TYPE_COL), row,
					type);
			sheet.addCell(eltinCell);

			if (conn.isIo()) {
				String indexIn = String.valueOf(conn.getConnectorIndex());
				WritableCell indexCell = new Label(
						getColumnNr(CN_INPUT_INDEX_COL), row, indexIn);
				sheet.addCell(indexCell);

			} else {
				String indexOut = String.valueOf(conn.getConnectorIndex());
				WritableCell indexCell = new Label(
						getColumnNr(CN_OUTPUT_INDEX_COL), row, indexOut);
				sheet.addCell(indexCell);
			}

		}
	}

	public void setHistory(List<HistoryItem> historyList)
			throws RowsExceededException, WriteException {
		WritableSheet sheet = workbook.createSheet(getProperty(HISTORY_SHEET),
				sheetIndex++);
		String[] propertiesList = { HIST_AUTHOR_COL, HIST_COMMENT_COL,
				HIST_DATE_COL, HIST_MODULE_COL, HIST_ELEMENT_COL };

		Map<String, Integer> columnMap = getColumnMap(propertiesList);
		for (String columnName : columnMap.keySet()) {
			WritableCell headerCell = new Label(columnMap.get(columnName), 0,
					columnName);
			sheet.addCell(headerCell);
		}

		for (int i = 0; i < historyList.size(); i++) {
			HistoryItem hi = historyList.get(i);

			String author = hi.getAuthor();
			int row = i + HEADER_ROWS_NR;
			WritableCell authorCell = new Label(getColumnNr(HIST_AUTHOR_COL),
					row, author);
			sheet.addCell(authorCell);

			String desc = hi.getDescription();
			WritableCell descCell = new Label(getColumnNr(HIST_COMMENT_COL),
					row, desc);
			sheet.addCell(descCell);

			String date = dateFormat.format(hi.getCreationDate());
			WritableCell dateCell = new Label(getColumnNr(HIST_DATE_COL), row,
					date);
			sheet.addCell(dateCell);

			if (hi instanceof StructureHistoryItem) {
				StructureHistoryItem shi = (StructureHistoryItem) hi;

				String ve = shi.getVirtualElement() == null ? "" : shi
						.getVirtualElement().getName();
				WritableCell veCell = new Label(getColumnNr(HIST_ELEMENT_COL),
						row, ve);
				sheet.addCell(veCell);
			}

			if (hi instanceof ModuleHistoryItem) {
				ModuleHistoryItem mhi = (ModuleHistoryItem) hi;

				String pe = mhi.getPhysicalElement() == null ? "" : mhi
						.getPhysicalElement().getLabel();
				WritableCell peCell = new Label(getColumnNr(HIST_MODULE_COL),
						row, pe);
				sheet.addCell(peCell);
			}
		}
	}

	public void setModules(List<PhysicalElement> modules)
			throws RowsExceededException, WriteException {
		WritableSheet sheet = workbook.createSheet(getProperty(MODULES_SHEET),
				sheetIndex++);
		String[] propertiesList = { ELT_ID_COL, ELT_LABEL_COL, ELT_TYPE_COL };

		int lastColumnNr = 0;
		Map<String, Integer> columnMap = getColumnMap(propertiesList);
		for (String columnName : columnMap.keySet()) {
			WritableCell headerCell = new Label(columnMap.get(columnName), 0,
					columnName);
			sheet.addCell(headerCell);
			if (columnMap.get(columnName) > lastColumnNr)
				lastColumnNr = columnMap.get(columnName);
		}

		for (int i = 0; i < modules.size(); i++) {
			PhysicalElement pe = modules.get(i);

			String id = pe.getVirtualElement() == null ? "" : pe
					.getVirtualElement().getName();
			int row = i + HEADER_ROWS_NR;
			WritableCell idCell = new Label(getColumnNr(ELT_ID_COL), row, id);
			sheet.addCell(idCell);

			String type = pe.getElementType().getTypeName();
			WritableCell typeCell = new Label(getColumnNr(ELT_TYPE_COL), row,
					type);
			sheet.addCell(typeCell);

			String label = pe.getLabel();
			WritableCell labelCell = new Label(getColumnNr(ELT_LABEL_COL), row,
					label);
			sheet.addCell(labelCell);

			List<Attribute> attrs = new LinkedList<Attribute>();
			attrs.addAll(pe.getAttributes());
			for (int j = 0; j < attrs.size(); j++) {
				String attr = attrs.get(j).getFieldName() + ":"
						+ attrs.get(j).getValue();
				WritableCell attrCell = new Label(j
						+ getColumnNr(ELT_ATTRIBUTES_COL), row, attr);
				sheet.addCell(attrCell);
			}
		}

	}

	// public void setInternalConnections(List<ElementType> types) throws
	// RowsExceededException, WriteException{
	// WritableSheet sheet =
	// workbook.createSheet(getProperty(INTERNAL_CONNECTIONS_SHEET),
	// sheetIndex++);
	// String[] propertiesList = {
	// IC_INPUT_ID_COL, IC_OUTPUT_ID_COL, IC_TYPE_COL
	// };
	//		
	// Map<String, Integer> columnMap = getColumnMap(propertiesList);
	// for (String columnName : columnMap.keySet()) {
	// WritableCell headerCell = new Label(columnMap.get(columnName), 0,
	// columnName);
	// sheet.addCell(headerCell);
	// }
	//		
	// int row = 0;
	// for (int i = 0; i < types.size(); i++) {
	// ElementType type = types.get(i);
	// Set<InternalConnection> conns = type.getInternalConnections();
	// for (InternalConnection internalConnection : conns) {
	// String in = "" + internalConnection.getPositionIn();
	// WritableCell inCell = new Label(getColumnNr(IC_INPUT_ID_COL), row + 1,
	// in);
	// sheet.addCell(inCell);
	//				
	// String out = "" + internalConnection.getPositionOut();
	// WritableCell outCell = new Label(getColumnNr(IC_OUTPUT_ID_COL), row + 1,
	// out);
	// sheet.addCell(outCell);
	//				
	// String typeId = internalConnection.getType() == null ? "" :
	// internalConnection.getType().getTypeName();
	// WritableCell idCell = new Label(getColumnNr(IC_TYPE_COL), row + 1,
	// typeId);
	// sheet.addCell(idCell);
	//				
	// row++;
	// }
	// }
	// }

	public void setStructure(List<VirtualElement> elements)
			throws RowsExceededException, WriteException {
		WritableSheet sheet = workbook.createSheet(
				getProperty(STRUCTURE_SHEET), sheetIndex++);
		String[] propertiesList = { STRUCT_ID_COL, STRUCT_PARENT_COL,
				STRUCT_TYPE_COL, STRUCT_LOCATION_COL };

		Map<String, Integer> columnMap = getColumnMap(propertiesList);
		for (String columnName : columnMap.keySet()) {
			WritableCell headerCell = new Label(columnMap.get(columnName), 0,
					columnName);
			sheet.addCell(headerCell);
		}

		for (int i = 0; i < elements.size(); i++) {
			VirtualElement elt = elements.get(i);
			String name = elt.getName();
			int row = i + HEADER_ROWS_NR;
			WritableCell nameCell = new Label(getColumnNr(STRUCT_ID_COL), row,
					name);
			sheet.addCell(nameCell);

			String parent = elt.getParent() == null ? "" : elt.getParent()
					.getName();
			WritableCell cableCell = new Label(getColumnNr(STRUCT_PARENT_COL),
					row, parent);
			sheet.addCell(cableCell);

			String type = elt.getElementType().getTypeName();
			WritableCell typeCell = new Label(getColumnNr(STRUCT_TYPE_COL),
					row, type);
			sheet.addCell(typeCell);

			String location = "" + elt.getLocation();
			WritableCell locationCell = new Label(
					getColumnNr(STRUCT_LOCATION_COL), row, location);
			sheet.addCell(locationCell);

		}
	}

	public void save() throws IOException, WriteException {
		workbook.write();
		workbook.close();
	}
}
